package helmsvc

import (
	"errors"
	"fmt"
	corev1 "gluenet/internal/agent/api/core/v1"
	"gluenet/internal/agent/driver/k8sdriver/option"

	"helm.sh/helm/v3/pkg/release"
)

func (svc *Service) CreateHelmRelease(release *corev1.HelmRelease) corev1.CommonResp {
	var (
		err              error
		releaseDetialObj *corev1.HelmReleaseObj
	)

	if releaseDetialObj, err = svc.createHelmRelease(release); err != nil {
		goto ErrProcess
	}

	if release.Options.WithJaeger {
		err = svc.injectJaeger(release.GluenetGuid)
	}

	if err != nil {
		goto ErrProcess
	}

	releaseDetialObj.Ready()
	if err = svc.objects.Put(
		release.GluenetGuid,
		release.GluenetKind,
		releaseDetialObj,
	); err != nil {
		goto ErrProcess
	}

	return corev1.NewCommonSuccessRespWithData(releaseDetialObj)

ErrProcess:
	svc.logger.Errorf(err.Error())
	svc.kd.DeleteNameSpace(release.GluenetGuid)
	return corev1.NewCommonFailureResp(err.Error())
}

func (svc *Service) createHelmRelease(rls *corev1.HelmRelease) (releaseDetailObj *corev1.HelmReleaseObj, err error) {
	var releaseDetial *release.Release

	if svc.objects.IsExist(rls.GluenetGuid, rls.GluenetKind) ||
		svc.kd.IsNameSpaceExist(rls.GluenetGuid) {
		return nil, errors.New("duplicated resource")
	}

	if err = svc.kd.CreateNameSpace(rls.GluenetGuid); err != nil {
		return
	}

	if releaseDetial, err = svc.hd.Install(rls.GluenetGuid, rls.Spec); err != nil {
		return
	}

	return &corev1.HelmReleaseObj{
		GluenetMeta: rls.GluenetMeta,
		Spec: corev1.ReleaseDetial{
			Containers: svc.kd.ParseMainfest(releaseDetial.Manifest),
			Release:    releaseDetial,
		},
		Status: corev1.NewState(),
	}, nil
}

func (svc *Service) injectJaeger(appGuid string) error {
	svc.logger.Infof("inject jaeger to %s", appGuid)
	svc.logger.Debugf("%s", svc.jaegerRelease.Release)
	if _, err := svc.hd.Install(
		appGuid,
		svc.jaegerRelease.Release,
	); err != nil {
		return fmt.Errorf("inject jaeger to %s failed: %s", appGuid, err)
	}

	return nil
}

func (svc *Service) GetHelmRelease(meta *corev1.GluenetMeta) corev1.CommonResp {
	var releaseDetial *release.Release
	var containers []string

	obj, err := svc.objects.Get(meta.GluenetGuid, meta.GluenetKind)
	releaseDetailObj, ok := obj.(*corev1.HelmReleaseObj)

	if err != nil && !ok {
		goto ErrProcess
	}

	if releaseDetial, err = svc.hd.
		GetRelease(
			meta.GluenetGuid,
			releaseDetailObj.Spec.Name,
		); err != nil {
		goto ErrProcess
	}

	if containers, err = svc.kd.
		ListPods(
			meta.GluenetGuid,
			option.ListOptions{},
		).ContainerList(); err != nil {
		goto ErrProcess
	}

	releaseDetailObj.Spec.Release = releaseDetial
	releaseDetailObj.Spec.Containers = containers

	return corev1.NewCommonSuccessRespWithData(releaseDetailObj)

ErrProcess:
	svc.logger.Errorf(err.Error())
	return corev1.NewCommonFailureResp(err.Error())

}

func (svc *Service) DeleteHelmRelease(meta *corev1.GluenetMeta) corev1.CommonResp {
	obj, err := svc.objects.Get(meta.GluenetGuid, meta.GluenetKind)
	releaseDetialObj, ok := obj.(*corev1.HelmReleaseObj)

	if err != nil && !ok {
		goto ErrProcess
	} else {
		releaseDetialObj.Terminating()
	}

	if err := svc.kd.DeleteNameSpace(meta.GluenetGuid); err != nil {
		goto ErrProcess
	} else {
		releaseDetialObj.Terminated()
	}

	if err := svc.objects.DeleteAll(meta.GluenetGuid); err != nil {
		goto ErrProcess
	}

	return corev1.NewCommonSuccessRespWithData(nil)

ErrProcess:
	svc.logger.Errorf(err.Error())
	return corev1.NewCommonFailureResp(err.Error())
}
